home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
LANG
/
LISP
/
XLISP
/
XLISP21S
/
sources
/
c
/
xldmem
< prev
next >
Wrap
Text File
|
1992-04-25
|
22KB
|
917 lines
/* xldmem - xlisp dynamic memory management routines */
/* Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xlisp.h"
/* node flags */
#define MARK 0x20
#define LEFT 0x40
/* macro to compute the size of a segment */
#define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node))
/* external variables */
extern LVAL obarray,s_gcflag,s_gchook,s_unbound,s_debugio,true;
extern LVAL xlenv,xlfenv,xldenv;
/* variables local to xldmem.c and xlimage.c */
SEGMENT *segs,*lastseg,*fixseg,*charseg;
int anodes,nsegs;
long gccalls;
long nnodes,nfree,total;
LVAL fnodes = NIL;
/* forward declarations */
#ifdef ANSI
#ifdef JMAC
FORWARD LVAL NEAR Newnode(int type);
#else
FORWARD LVAL NEAR newnode(int type);
#endif
FORWARD char * NEAR stralloc(unsigned int size);
FORWARD VOID NEAR mark(LVAL ptr);
FORWARD VOID NEAR sweep(void);
FORWARD VOID NEAR findmem(void);
FORWARD int NEAR addseg(void);
#else
#ifdef JMAC
FORWARD LVAL Newnode();
#else
FORWARD LVAL newnode();
#endif
FORWARD char *stralloc();
FORWARD VOID mark();
FORWARD VOID sweep();
FORWARD VOID findmem();
#endif
#ifdef JMAC
LVAL _nnode = NIL;
FIXTYPE _tfixed = 0;
int _tint = 0;
#define newnode(type) (((_nnode = fnodes) != NIL) ? \
((fnodes = cdr(_nnode)), \
nfree--, \
(_nnode->n_type = type), \
rplacd(_nnode,NIL), \
_nnode) \
: Newnode(type))
#endif
/* $putpatch.c$: "MODULE_XLDMEM_C_GLOBALS" */
#ifdef VMEM
LOCAL VOID gcq(size)
long size;
{
if ((total+size)/VMEM > total/VMEM) gc();
}
#endif
/* xlminit - initialize the dynamic memory module */
VOID xlminit()
{
LVAL p;
int i;
/* initialize our internal variables */
segs = lastseg = NULL;
nnodes = nfree = total = gccalls = 0L;
nsegs = 0;
anodes = NNODES;
fnodes = NIL;
/* allocate the fixnum segment */
if ((fixseg = newsegment(SFIXSIZE)) == NULL)
xlfatal("insufficient memory");
/* initialize the fixnum segment */
p = &fixseg->sg_nodes[0];
for (i = SFIXMIN; i <= SFIXMAX; ++i) {
p->n_type = FIXNUM;
p->n_fixnum = i;
++p;
}
/* allocate the character segment */
if ((charseg = newsegment(CHARSIZE)) == NULL)
xlfatal("insufficient memory");
/* initialize the character segment */
p = &charseg->sg_nodes[0];
for (i = CHARMIN; i <= CHARMAX; ++i) {
p->n_type = CHAR;
p->n_chcode = i;
++p;
}
/* initialize structures that are marked by the collector */
obarray = NULL;
xlenv = xlfenv = xldenv = NIL;
s_gcflag = s_gchook = NULL;
/* $putpatch.c$: "MODULE_XLDMEM_C_XLMINIT" */
/* allocate the evaluation stack */
xlstack = xlstktop;
/* allocate the argument stack */
xlfp = xlsp = xlargstkbase;
*xlsp++ = NIL;
/* we have to make a NIL symbol before continuing */
p = xlmakesym("NIL");
memcpy(NIL, p, sizeof(struct node)); /* we point to this! */
defconstant(NIL, NIL);
p->n_type = FREE; /* don't collect "garbage" */
}
/* cons - construct a new cons node */
LVAL cons(x,y)
LVAL x,y;
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
xlstkcheck(2);
xlprotect(x);
xlprotect(y);
findmem();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
xlpop();
xlpop();
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
--nfree;
/* initialize the new node */
nnode->n_type = CONS;
rplaca(nnode,x);
rplacd(nnode,y);
/* return the new node */
return (nnode);
}
/* cvstring - convert a string to a string node */
LVAL cvstring(str)
char *str;
{
LVAL val;
xlsave1(val);
val = newnode(STRING);
val->n_strlen = strlen(str);
val->n_string = stralloc(getslength(val)+1);
strcpy((char *)getstring(val),str);
xlpop();
return (val);
}
/* newstring - allocate and initialize a new string */
LVAL newstring(size)
unsigned size;
{
LVAL val;
xlsave1(val);
val = newnode(STRING);
val->n_strlen = size;
val->n_string = stralloc(size+1);
val->n_string[0] = 0;
xlpop();
return (val);
}
/* cvsymbol - convert a string to a symbol */
LVAL cvsymbol(pname)
char *pname;
{
LVAL val;
xlsave1(val);
val = newvector(SYMSIZE);
val->n_type = SYMBOL;
setvalue(val,s_unbound);
setfunction(val,s_unbound);
setpname(val,cvstring(pname));
xlpop();
return (val);
}
/* cvsubr - convert a function to a subr or fsubr */
#ifdef ANSI
LVAL cvsubr(LVAL (*fcn)(void), int type, int offset)
#else
LVAL cvsubr(fcn,type,offset)
LVAL (*fcn)(); int type,offset;
#endif
{
LVAL val;
val = newnode(type);
val->n_subr = fcn;
val->n_offset = offset;
return (val);
}
/* cvfile - convert a file pointer to a stream */
LVAL cvfile(fp, iomode)
FILEP fp;
int iomode;
{
LVAL val;
val = newnode(STREAM);
setfile(val,fp);
setsavech(val,'\0');
val->n_sflags = iomode;
val->n_cpos = 0;
return (val);
}
#ifdef JMAC
/* cvfixnum - convert an integer to a fixnum node */
LVAL Cvfixnum(n)
FIXTYPE n;
{
LVAL val;
val = newnode(FIXNUM);
val->n_fixnum = n;
return (val);
}
#else
/* cvfixnum - convert an integer to a fixnum node */
LVAL cvfixnum(n)
FIXTYPE n;
{
LVAL val;
if (n >= SFIXMIN && n <= SFIXMAX)
return (&fixseg->sg_nodes[(int)n-SFIXMIN]);
val = newnode(FIXNUM);
val->n_fixnum = n;
return (val);
}
#endif
/* cvflonum - convert a floating point number to a flonum node */
LVAL cvflonum(n)
FLOTYPE n;
{
LVAL val;
val = newnode(FLONUM);
val->n_flonum = n;
return (val);
}
/* cvchar - convert an integer to a character node */
#ifdef JMAC
LVAL Cvchar(n)
int n;
{
xlerror("character code out of range",cvfixnum((FIXTYPE)n));
return(NIL); /* never executed */
}
#else
LVAL cvchar(n)
int n;
{
if (n >= CHARMIN && n <= CHARMAX)
return (&charseg->sg_nodes[n-CHARMIN]);
xlerror("character code out of range",cvfixnum((FIXTYPE)n));
return 0; /* never executed but gets rid of warning message */
}
#endif
#ifdef RATIOS
/* cvratio - convert an integer pair to a ratio node */
LVAL cvratio(num, denom)
FIXTYPE num, denom;
{
LVAL val;
FIXTYPE n, m, r;
if (num == 0) return cvfixnum((FIXTYPE) 0); /* zero is int zero */
if (denom < 0) { /* denominator must be positive */
denom = -denom;
num = -num;
}
if ((n = num) < 0) n = -n;
m = denom; /* reduce the ratio: compute GCD */
for (;;) {
if ((r = m % n) == 0) break;
m = n;
n = r;
}
if (n != 1) {
denom /= n;
num /= n;
}
if (denom == 1) return cvfixnum(num); /* reduced to integer */
val = newnode(RATIO);
val->n_denom = denom;
val->n_numer = num;
return (val);
}
#endif
/* newustream - create a new unnamed stream */
LVAL newustream()
{
LVAL val;
val = newnode(USTREAM);
sethead(val,NIL);
settail(val,NIL);
return (val);
}
/* newobject - allocate and initialize a new object */
LVAL newobject(cls,size)
LVAL cls; int size;
{
LVAL val;
val = newvector(size+1);
val->n_type = OBJECT;
setelement(val,0,cls);
return (val);
}
/* newclosure - allocate and initialize a new closure */
LVAL newclosure(name,type,env,fenv)
LVAL name,type,env,fenv;
{
LVAL val;
val = newvector(CLOSIZE);
val->n_type = CLOSURE;
setname(val,name);
settype(val,type);
setenvi(val,env);
setfenv(val,fenv);
return (val);
}
/* newstruct - allocate and initialize a new structure node */
LVAL newstruct(type,size)
LVAL type; int size;
{
LVAL val;
val = newvector(size+1);
val->n_type = STRUCT;
setelement(val,0,type);
return (val);
}
/* newvector - allocate and initialize a new vector node */
LVAL newvector(size)
unsigned size;
{
LVAL vect;
int i;
long bsize = size * sizeof(LVAL *);
if (size > MAXVLEN) xlfail("array too large");
xlsave1(vect);
vect = newnode(VECTOR);
vect->n_vsize = 0;
if (size != 0) {
/* We must clear to a nonzero value */
#ifdef VMEM
gcq(bsize);
#endif
if ((vect->n_vdata = (LVAL *)MALLOC((unsigned int)bsize)) == NULL) {
gc(); /* TAA Mod -- was findmem(), but this would
cause undesired memory expansion */
if ((vect->n_vdata = (LVAL *)MALLOC((unsigned int)bsize)) == NULL)
xlfail("insufficient vector space");
}
for (i = size; i-- > 0;) setelement(vect, i, NIL);
vect->n_vsize = size;
total += bsize;
}
xlpop();
return (vect);
}
/* newnode - allocate a new node */
#ifdef JMAC
LOCAL LVAL NEAR Newnode(type)
int type;
{
LVAL nnode;
/* get a free node */
findmem();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
/* unlink the node from the free list */
fnodes = cdr(nnode);
nfree -= 1L;
/* initialize the new node */
nnode->n_type = type;
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
#else
LOCAL LVAL NEAR newnode(type)
int type;
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
findmem();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
nfree -= 1L;
/* initialize the new node */
nnode->n_type = type;
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
#endif
/* stralloc - allocate memory for a string */
LOCAL char * NEAR stralloc(size)
unsigned int size;
{
char *sptr;
#ifdef VMEM
gcq((long)size);
#endif
/* allocate memory for the string copy */
if ((sptr = (char *)MALLOC(size)) == NULL) {
gc();
if ((sptr = (char *)MALLOC(size)) == NULL)
xlfail("insufficient string space");
}
total += (long)size;
/* return the new string memory */
return (sptr);
}
/* findmem - find more memory by collecting then expanding */
LOCAL VOID NEAR findmem()
{
gc();
if (nfree < (long)anodes)
addseg();
}
/* gc - garbage collect (only called here and in xlimage.c) */
VOID gc()
{
register LVAL **p,*ap,tmp;
FRAMEP newfp;
LVAL fun;
/* print the start of the gc message */
if (s_gcflag != NULL && getvalue(s_gcflag) != NIL) {
/* print message on a fresh line */
xlfreshline(getvalue(s_debugio));
sprintf(buf,"[ gc: total %ld, ",nnodes);
dbgputstr(buf); /* TAA MOD -- was std output */
}
/* $putpatch.c$: "MODULE_XLDMEM_C_GC" */
/* mark the obarray, the argument list and the current environment */
if (obarray != NULL)
mark(obarray);
if (xlenv != NIL)
mark(xlenv);
if (xlfenv != NIL)
mark(xlfenv);
if (xldenv != NIL)
mark(xldenv);
mark(NIL);
/* mark the evaluation stack */
for (p = xlstack; p < xlstktop; ++p)
if ((tmp = **p) != NIL)
mark(tmp);
/* mark the argument stack */
for (ap = xlargstkbase; ap < xlsp; ++ap)
if ((tmp = *ap) != NIL)
mark(tmp);
/* sweep memory collecting all unmarked nodes */
sweep();
NIL->n_type &= ~MARK;
/* count the gc call */
++gccalls;
/* call the *gc-hook* if necessary */
if (s_gchook != NULL && ((fun = getvalue(s_gchook)) != NIL) ) {
/* rebind hook function to NIL TAA MOD */
tmp = xldenv;
xldbind(s_gchook,NIL);
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(fun);
pusharg(cvfixnum((FIXTYPE)2));
pusharg(cvfixnum((FIXTYPE)nnodes));
pusharg(cvfixnum((FIXTYPE)nfree));
xlfp = newfp;
xlapply(2);
/* unbind the symbol TAA MOD */
xlunbind(tmp);
}
/* print the end of the gc message */
if (s_gcflag != NULL && getvalue(s_gcflag) != NIL) {
sprintf(buf,"%ld free ]\n",nfree);
dbgputstr(buf); /* TAA MOD -- was std output */
}
}
/* mark - mark all accessible nodes */
LOCAL VOID NEAR mark(ptr)
LVAL ptr;
{
register LVAL this,prev,tmp;
int i,n;
/* initialize */
prev = NIL;
this = ptr;
/* mark this list */
for (;;) {
/* descend as far as we can */
while (!(this->n_type & MARK))
/* check cons and unnamed stream nodes */
if (((i = (this->n_type |= MARK) & TYPEFIELD) == CONS)||
(i == USTREAM)) {
if ((tmp = car(this)) != NIL) {
this->n_type |= LEFT;
rplaca(this,prev);
}
else if ((tmp = cdr(this)) != NIL)
rplacd(this,prev);
else /* both sides nil */
break;
prev = this; /* step down the branch */
this = tmp;
}
/* $putpatch.c$: "MODULE_XLDMEM_C_MARK" */
else {
if ((i & ARRAY) != 0)
for (i = 0, n = getsize(this); i < n;)
if ((tmp = getelement(this,i++)) != NIL)
if ((tmp->n_type & (ARRAY|MARK)) == ARRAY ||
tmp->n_type == CONS ||
tmp->n_type == USTREAM)
mark(tmp);
else tmp->n_type |= MARK;
break;
}
/* backup to a point where we can continue descending */
for (;;)
/* make sure there is a previous node */
if (prev != NIL) {
if (prev->n_type & LEFT) { /* came from left side */
prev->n_type &= ~LEFT;
tmp = car(prev);
rplaca(prev,this);
if ((this = cdr(prev)) != NIL) {
rplacd(prev,tmp);
break;
}
}
else { /* came from right side */
tmp = cdr(prev);
rplacd(prev,this);
}
this = prev; /* step back up the branch */
prev = tmp;
}
/* no previous node, must be done */
else
return;
}
}
/* sweep - sweep all unmarked nodes and add them to the free list */
LOCAL VOID NEAR sweep()
{
SEGMENT *seg;
LVAL p;
int n;
/* empty the free list */
fnodes = NIL;
nfree = 0L;
/* add all unmarked nodes */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
if (seg == fixseg || seg == charseg) {
/* remove marks from segments */
p = &seg->sg_nodes[0];
for (n = seg->sg_size; --n >= 0;)
(p++)->n_type &= ~MARK;
continue;
}
p = &seg->sg_nodes[0];
for (n = seg->sg_size; --n >= 0;)
if (p->n_type & MARK)
(p++)->n_type &= ~MARK;
else {
switch (ntype(p)&TYPEFIELD) {
case STRING:
if (getstring(p) != NULL) {
total -= (long)getslength(p)+1;
MFREE(getstring(p));
}
break;
case STREAM:
if (getfile(p) != CLOSED
&& getfile(p) != STDIN
&& getfile(p) != STDOUT
&& getfile(p) != CONSOLE)/* taa fix - dont close stdio */
OSCLOSE(getfile(p));
break;
/* $putpatch.c$: "MODULE_XLDMEM_C_SWEEP" */
case SYMBOL:
case OBJECT:
case VECTOR:
case CLOSURE:
case STRUCT:
#ifdef COMPLX
case COMPLEX:
#endif
if (p->n_vsize) {
total -= (long)p->n_vsize * sizeof(LVAL);
MFREE(p->n_vdata);
}
break;
}
p->n_type = FREE;
rplaca(p,NIL);
rplacd(p,fnodes);
fnodes = p++;
nfree++;
}
}
}
/* addseg - add a segment to the available memory */
LOCAL int NEAR addseg()
{
SEGMENT *newseg;
LVAL p;
int n;
/* allocate the new segment */
if (anodes == 0 || (newseg = newsegment(anodes)) == NULL)
return (FALSE);
/* add each new node to the free list */
p = &newseg->sg_nodes[0];
for (n = anodes; --n >= 0; ++p) {
rplacd(p,fnodes);
fnodes = p;
}
/* return successfully */
return (TRUE);
}
/* newsegment - create a new segment (only called here and in xlimage.c) */
SEGMENT *newsegment(n)
int n;
{
SEGMENT *newseg;
/* allocate the new segment */
if ((newseg = (SEGMENT *)CALLOC(1,segsize(n))) == NULL)
return (NULL);
/* initialize the new segment */
newseg->sg_size = n;
newseg->sg_next = NULL;
if (segs != NULL)
lastseg->sg_next = newseg;
else
segs = newseg;
lastseg = newseg;
/* update the statistics */
total += (long)segsize(n);
nnodes += (long)n;
nfree += (long)n;
++nsegs;
/* return the new segment */
return (newseg);
}
/* stats - print memory statistics */
#ifdef ANSI
static void NEAR stats(void)
#else
LOCAL VOID stats()
#endif
{
sprintf(buf,"Nodes: %ld\n",nnodes); stdputstr(buf);
sprintf(buf,"Free nodes: %ld\n",nfree); stdputstr(buf);
sprintf(buf,"Segments: %d\n",nsegs); stdputstr(buf);
sprintf(buf,"Allocate: %d\n",anodes); stdputstr(buf);
sprintf(buf,"Total: %ld\n",total); stdputstr(buf);
sprintf(buf,"Collections: %ld\n",gccalls); stdputstr(buf);
}
/* xgc - xlisp function to force garbage collection */
LVAL xgc()
{
/* make sure there aren't any arguments */
xllastarg();
/* garbage collect */
gc();
/* return nil */
return (NIL);
}
/* xexpand - xlisp function to force memory expansion */
LVAL xexpand()
{
LVAL num;
FIXTYPE n,i;
/* get the new number to allocate */
if (moreargs()) {
num = xlgafixnum();
n = getfixnum(num);
/* make sure there aren't any more arguments */
xllastarg();
}
else
n = 1;
/* allocate more segments */
for (i = 0; i < n; i++)
if (!addseg())
break;
/* return the number of segments added */
return (cvfixnum((FIXTYPE)i));
}
/* xalloc - xlisp function to set the number of nodes to allocate */
LVAL xalloc()
{
FIXTYPE n; /* TAA MOD -- prevent overflow */
int oldn;
/* get the new number to allocate */
n = getfixnum(xlgafixnum());
/* make sure there aren't any more arguments */
if (xlargc > 1) xltoomany(); /* but one more is OK, TAA MOD */
/* Place limits on argument by clipping to reasonable values TAA MOD */
if (n > ((long)MAXSLEN - sizeof(SEGMENT))/sizeof(struct node))
n = ((long)MAXSLEN - sizeof(SEGMENT))/sizeof(struct node);
else if (n < 1000)
n = 1000; /* arbitrary */
/* set the new number of nodes to allocate */
oldn = anodes;
anodes = (int)n;
/* return the old number */
return (cvfixnum((FIXTYPE)oldn));
}
/* xmem - xlisp function to print memory statistics */
LVAL xmem()
{
/* allow one argument for compatiblity with common lisp */
if (xlargc > 1) xltoomany(); /* TAA Mod */
/* print the statistics */
stats();
/* return nil */
return (NIL);
}
#ifdef SAVERESTORE
/* xsave - save the memory image */
LVAL xsave()
{
char *name;
/* get the file name, verbose flag and print flag */
name = getstring(xlgetfname());
xllastarg();
/* save the memory image */
return (xlisave(name) ? true : NIL);
}
/* xrestore - restore a saved memory image */
LVAL xrestore()
{
extern jmp_buf top_level;
char *name;
/* get the file name, verbose flag and print flag */
name = getstring(xlgetfname());
xllastarg();
/* restore the saved memory image */
if (!xlirestore(name))
return (NIL);
/* return directly to the top level */
dbgputstr("[ returning to the top level ]\n"); /* TAA MOD --was std out*/
longjmp(top_level,1);
return (NIL); /* never executed, but avoids warning message */
}
#endif
#ifdef COMPLX
/* From XLISP-STAT, Copyright (c) 1988 Luke Tierney */
LVAL newicomplex(real, imag)
FIXTYPE real, imag;
{
LVAL val;
if (imag == 0) val = cvfixnum(real);
else {
xlsave1(val);
val = newvector(2);
val->n_type = COMPLEX;
setelement(val, 0, cvfixnum(real));
setelement(val, 1, cvfixnum(imag));
xlpop();
}
return(val);
}
LVAL newdcomplex(real, imag)
double real, imag;
{
LVAL val;
xlsave1(val);
val = newvector(2);
val->n_type = COMPLEX;
setelement(val, 0, cvflonum((FLOTYPE) real));
setelement(val, 1, cvflonum((FLOTYPE) imag));
xlpop();
return(val);
}
/* newcomplex - allocate and initialize a new object */
LVAL newcomplex(real,imag)
LVAL real,imag;
{
if (fixp(real) && fixp(imag))
return(newicomplex(getfixnum(real), getfixnum(imag)));
else
return(newdcomplex(makefloat(real), makefloat(imag)));
}
#endif